package com.yuandian.utils;

import lombok.extern.slf4j.Slf4j;

import java.math.BigInteger;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * IP转换工具类
 */
@Slf4j
public class IpUtils {

	/**
	 * 判断ip是否在指定网段
	 *
	 * @param ip
	 * @return
	 */
	public static boolean ipIsInNet(String ip, String ipArea) {
		if ("127.0.0.1".equals(ip)) {
			return true;
		}

		if(StringUtils.isBlank(ipArea)){
			return false;
		}

		String[] ipArray = ipArea.split(",");
		for (String s : ipArray) {
			if (!s.contains("/")) {
				if (s.equals(ip)) {
					return true;
				}
				continue;
			}

			String[] ips = ip.split("\\.");
			//ip地址的十进制值
			int ipAddress = (Integer.parseInt(ips[0]) << 24)
					| (Integer.parseInt(ips[1]) << 16)
					| (Integer.parseInt(ips[2]) << 8) | Integer.parseInt(ips[3]);
			//掩码（0-32）
			int type = Integer.parseInt(s.replaceAll(".*/", ""));
			//匹配的位数为32 - type位（16进制的1）
			int mask = 0xFFFFFFFF << (32 - type);
			String cidrIp = s.replaceAll("/.*", "");
			//网段ip十进制
			String[] cidrIps = cidrIp.split("\\.");
			int cidrIpAddr = (Integer.parseInt(cidrIps[0]) << 24)
					| (Integer.parseInt(cidrIps[1]) << 16)
					| (Integer.parseInt(cidrIps[2]) << 8)
					| Integer.parseInt(cidrIps[3]);

			if((ipAddress & mask) == (cidrIpAddr & mask)){
				return true;
			}
			continue;
		}
		return false;
	}

	/**
	 * 判断ip是否在该网段
	 *
	 * @param ip
	 *            ip地址 （如：192.168.1.1）
	 * @param netMask
	 *            网段字符串（格式：192.168.1.1/24）
	 * @return true 在 false 不在
	 */
	public static boolean ipInRange(String ip, String netMask) {
		long[] range = getIpRange(netMask);
		long ip_long = ip2Long2(ip);
		// System.out.println("ip:"+ip_long+"ipMin:"+range[0]+"ipMax:"+range[1]);
		if (ip_long < range[1] && ip_long > range[0]) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 得到网段范围
	 *
	 * @param netPart
	 *            网段（格式：192.168.1.1/24）
	 * @return
	 */
	public static long[] getIpRange(String netPart) {
		// 192.168.1.1/24
		String[] ips = netPart.split("/");
		long[] range = new long[2];
		long base32_1 = 4294967295l;
		long ip_long = ip2Long2(ips[0]);
		int ones = Integer.parseInt(ips[1]);
		long min32_1 = base32_1 << (32 - ones);
		long max32_1 = base32_1 >> ones;
		// System.out.println(ip_long);
		// System.out.println(Long.toBinaryString(min32_1));
		// System.out.println(Long.toBinaryString(max32_1));
		range[0] = ip_long & min32_1;
		range[1] = ip_long | max32_1;
		return range;
	}

	/**
	 * 得到网段范围
	 *
	 * @param netPart
	 *            网段（格式：192.168.1.1/24）
	 * @return
	 */
	public static List<long[]> getIpRangeList(String netPart) {
		List<long[]> retlist = new ArrayList<long[]>();
		// 192.168.1.1/24
		String[] ips = netPart.split("/");
		if(ips.length > 1){
			long[] range = new long[2];
			long base32_1 = 4294967295l;
			long ip_long = ip2Long2(ips[0]);
			int ones = Integer.parseInt(ips[1]);
			long min32_1 = base32_1 << (32 - ones);
			long max32_1 = base32_1 >> ones;
			// System.out.println(ip_long);
			// System.out.println(Long.toBinaryString(min32_1));
			// System.out.println(Long.toBinaryString(max32_1));
			range[0] = ip_long & min32_1;
			range[1] = ip_long | max32_1;
			retlist.add(range);
		}else{
			if(netPart.indexOf("-")>0){
				long[] range = new long[2];
				ips = netPart.split("-");
				range[0] = ip2Long2(ips[0]);
				range[1] = ip2Long2(ips[1]);
				retlist.add(range);
			}else if(netPart.indexOf(",")>0){
				ips = netPart.split(",");
				for(String ip : ips){
					long[] range = new long[2];
					range[0] = ip2Long2(ip);
					range[1] = ip2Long2(ip);
					retlist.add(range);
				}
			}else{
				long[] range = new long[2];
				range[0] = ip2Long2(ips[0]);
				range[1] = ip2Long2(ips[0]);
				retlist.add(range);
			}
		}
		return retlist;
	}

	/**
	 * ip转成整型
	 *
	 * @param ip
	 *            ip地址（如：192.168.1.1）
	 * @return
	 */
	public static long ip2Long2(String ip) {
		String[] parts = ip.split("\\.");
		long a = Long.parseLong(parts[0]);
		long b = Long.parseLong(parts[1]);
		long c = Long.parseLong(parts[2]);
		long d = Long.parseLong(parts[3]);
		return (a << 24) + (b << 16) + (c << 8) + d;
	}

	/**
	 * ip转成整型
	 *
	 * @param ip
	 *            ip地址（如：192.168.1.1）
	 * @return
	 */
	public static long ip2Long(String ip) {
		// ip第一个数位低8位 以此类推 和黄欣欣对应
		String[] parts = ip.split("\\.");
		long a = Long.parseLong(parts[0]);
		long b = Long.parseLong(parts[1]);
		long c = Long.parseLong(parts[2]);
		long d = Long.parseLong(parts[3]);
		return (a << 24) + (b << 16) + (c << 8) + (d);
	}

	/**
	 * 长整型ip转换为string
	 *
	 * @param ipLong long型ip
	 * @return
	 */
	public static String getLongIpToString(long ipLong) {
		// 32位低位取 第一个8位位ip第一个数 以此类推 和黄欣欣对应

		// long mask[] = {4278190080l,16711680l,65280l,255l};
		// 3232235873

		long mask = 0xff;
		long num = 0;
		StringBuffer ipInfo = new StringBuffer();
		for (int i = 0; i < 4; i++) {
			// num = (ipLong & mask[i])>>((3-i)*8);
			num = (ipLong >> ((3 - i) * 8)) & mask;
			ipInfo.append(num);
			if (i != 3) {
				ipInfo.append(".");
			}
		}
		return ipInfo.toString();
	}

	public static String byteArrayIp2String(byte[] ipByte) {
		StringBuffer strb = new StringBuffer();
		for (int i = 0; ipByte != null && i < ipByte.length; i++) {
			strb.append(ipByte[i] & 0xff);
			if (i != 3) {
				strb.append(".");
			}
		}
		return strb.toString();
	}

	/**
	 * int转String
	 *
	 * @param ipaddress
	 * @return
	 */
	public static String iplongToIp(long ipaddress) {
		StringBuffer sb = new StringBuffer("");
		sb.append(String.valueOf((ipaddress >>> 24)));
		sb.append(".");
		sb.append(String.valueOf((ipaddress & 0x00FFFFFF) >>> 16));
		sb.append(".");
		sb.append(String.valueOf((ipaddress & 0x0000FFFF) >>> 8));
		sb.append(".");
		sb.append(String.valueOf((ipaddress & 0x000000FF)));
		return sb.toString();
	}

	// 将许可中的功能byte[] 转化成 0 1 的int[]
	public static int[] byteArrayToIntArray(byte[] sources) {
		int[] funcs = new int[sources.length * 8];
		int[] temp = new int[] { 128, 64, 32, 16, 8, 4, 2, 1 };
		for (int i = 0; i < sources.length; i++) {
			byte b = sources[i];
			for (int j = 0; j < temp.length; j++) {
				if (temp[j] == (b & temp[j])) {
					funcs[i * 8 + j] = 1;
				} else {
					funcs[i * 8 + j] = 0;
				}
			}
		}
		return funcs;
	}


	/**
	 * 得到网段范围  判断时候有重复 的，如果有则不添加，没有则添加
	 *
	 * @param netPart
	 *            网段（格式：192.168.1.1/24）
	 * @return
	 */
	public static List<long[]> getIpRangeList2(String netPart,List<long[]> lon) {
		List<long[]> retlist = new ArrayList<long[]>();
		// 192.168.1.1/24
		String[] ips = netPart.split("/");
		if(ips.length > 1){
			long[] range = new long[2];
			long base32_1 = 4294967295l;
			long ip_long = ip2Long2(ips[0]);
			int ones = Integer.parseInt(ips[1]);
			long min32_1 = base32_1 << (32 - ones);
			long max32_1 = base32_1 >> ones;
			// System.out.println(ip_long);
			// System.out.println(Long.toBinaryString(min32_1));
			// System.out.println(Long.toBinaryString(max32_1));
			range[0] = ip_long & min32_1;
			range[1] = ip_long | max32_1;
			lon.add(range);

		}else{
			if(netPart.indexOf("-")>0){
				long[] range = new long[2];
				ips = netPart.split("-");
				range[0] = ip2Long2(ips[0]);
				range[1] = ip2Long2(ips[1]);
				lon.add(range);
			}else if(netPart.indexOf(",")>0){
				ips = netPart.split(",");
				for(String ip : ips){
					long[] range = new long[2];
					range[0] = ip2Long2(ip);
					range[1] = ip2Long2(ip);
					lon.add(range);
				}
			}else{
				long[] range = new long[2];
				range[0] = ip2Long2(ips[0]);
				range[1] = ip2Long2(ips[0]);
				lon.add(range);

			}
		}
		return lon;
	}

	public static String longToMac(Long macLong){
		// 将十进制格式的 MAC 地址转换为十六进制格式
		String hexMacAddress = Long.toHexString(macLong).toUpperCase();
		while (hexMacAddress.length() < 12) {
			hexMacAddress = "0" + hexMacAddress;
		}

		// 解析十六进制格式的 MAC 地址
		StringBuilder macAddressBuilder = new StringBuilder();
		for (int i = 0; i < hexMacAddress.length(); i += 2) {
			String octet = hexMacAddress.substring(i, i + 2);
			macAddressBuilder.append(octet);
			if (i < hexMacAddress.length() - 2) {
				macAddressBuilder.append("-");
			}
		}
		return macAddressBuilder.toString();
	}

	/**
	 * ipv6的地址转为BigInteger整数
	 * @param ipv6	IPv6地址
	 * @return	十进制IPv6
	 */
	public static BigInteger ipv6ToInt(String ipv6) {
		int compressIndex = ipv6.indexOf("::");
		if (compressIndex != -1)
		{
			String part1s = ipv6.substring(0, compressIndex);
			String part2s = ipv6.substring(compressIndex + 1);
			BigInteger part1 = ipv6ToInt(part1s);
			BigInteger part2 = ipv6ToInt(part2s);
			int part1hasDot = 0;
			char ch[] = part1s.toCharArray();
			for (char c : ch)
			{
				if (c == ':')
				{
					part1hasDot++;
				}
			}
			return part1.shiftLeft(16 * (7 - part1hasDot )).add(part2);
		}
		BigInteger big = BigInteger.ZERO;
		String[] str = ipv6.split(":");
		for (int i = 0; i < str.length; i++) {
			if (str[i].isEmpty())
			{
				str[i] = "0";
			}
			big = big.add(BigInteger.valueOf(Long.valueOf(str[i], 16))
					.shiftLeft(16 * (str.length - i - 1)));
		}
		return big;
	}

	/**
	 * 将BigInteger整数转为ipv6
	 * @param big	十进制IPv6
	 * @return	IPv6地址
	 */
	public static String intToipv6(BigInteger big){
		String str = "";
		BigInteger ff = BigInteger.valueOf(0xffff);
		for (int i = 0; i < 8 ; i++){
			str = big.and(ff).toString(16) + ":" + str;
			big = big.shiftRight(16);
		}
		str = str.substring(0, str.length() - 1);
		return str.replaceFirst("(^|:)(0+(:|$)){2,8}", "::");
	}


	/**
	 * 判断IP地址是否是IPv6
	 * @param ipStr	Ip地址
	 * @return 结果
	 */
	public static boolean isIPv6(String ipStr) {
		try {
			final InetAddress inetAddress = InetAddress.getByName(ipStr);
			return inetAddress instanceof Inet6Address;
		} catch (UnknownHostException e) {
			return false;
		}
	}



	/**
	 * 把 IPv4 或 IPv6 转成 十进制格式(字符串类型)
	 *
	 * 		注意：由于实时流会把 十进制的IPv6地址前面加上 '-', 所以此处要进行处理，如：
	 * 					“fe80::8218:44ff:fee7:be30” 转成 “338288524927261089663393215332003331632” 需再转成 “-338288524927261089663393215332003331632”
	 *
	 * @param ipStr	点分IPv4(xx.xx.xx.xx) 或 冒分IPv6(xxxx:xxxx:xxxx:xxxx)
	 * @return 结果集
	 */
	public static String ipToDecimal(String ipStr) {
		String ipDecimal = "";
		try {
			// 判断是IPv6 还是 IPv4
			ipDecimal = isIPv6(ipStr) ? ("-" + ipv6ToInt(ipStr)) : String.valueOf(ip2Long(ipStr));
		} catch (Exception e) {
			e.printStackTrace();
			log.error("IP转换十进制报错: {}", e.getMessage());
		}
		return ipDecimal;
	}


	/**
	 * 十进制IP转成 点分IPv4(xx.xx.xx.xx) 或 冒分IPv6(xxxx:xxxx:xxxx:xxxx)
	 * @param decimalIpAddress	十进制IP地址
	 * @return	结果
	 */
	public static String decimalIpToStr(String decimalIpAddress) {
		String ipAddress = "";
		try {
			//如果IP中包含“-”，说明是IPV6
			if (decimalIpAddress.contains("-")) {
				ipAddress = intToipv6(new BigInteger(decimalIpAddress.replace("-", "")));
			} else {
				ipAddress = iplongToIp(Long.parseLong(decimalIpAddress));
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error("十进制IP转换报错: {}", e.getMessage());
		}
		return ipAddress;
	}


	/**
	 * 校验IP格式
	 * @param ipAddress	IP地址 xx.xx.x.xx
	 */
	public static boolean isValidIPAddress(String ipAddress) {
		if ((ipAddress != null) && (!ipAddress.isEmpty())) {
			return Pattern.matches("^([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}$", ipAddress);
		}
		return false;
	}




	public static void main(String[] args) {
		System.out.println(isValidIPAddress("10.1.1.16") || isIPv6("10.1.1.16"));


		System.out.println("-338288524927261089663393215332003331632");
		System.out.println(ipToDecimal("fe80::8218:44ff:fee7:be30"));

		System.out.println("===========================================================");


		System.out.println("fe80::8218:44ff:fee7:be30");
		System.out.println(decimalIpToStr("-338288524927261089663393215332003331632"));

		System.out.println("===========================================================");

		System.out.println("182588420");
		System.out.println(ipToDecimal("10.226.20.4"));

		System.out.println("===========================================================");

		System.out.println("10.226.20.4");
		System.out.println(decimalIpToStr("182588420"));
	}


}



